using System.Collections.Concurrent;
using APITransLib.Contracts;

namespace ChatWithMulitAIServer.Data;

// Demo repository with in-memory store and seeded fake data. Replace with EF Core / Dapper later.
public class InMemoryChatRepository : IChatRepository
{
    private readonly ConcurrentDictionary<string, UserDto> _users = new();
    private readonly ConcurrentDictionary<string, GroupDto> _groups = new();
    private readonly ConcurrentDictionary<string, MessageDto> _messages = new();

    public InMemoryChatRepository()
    {
        // Seed some demo data
        var u1 = new UserDto { Id = Guid.NewGuid().ToString("N"), DisplayName = "Alice" };
        var u2 = new UserDto { Id = Guid.NewGuid().ToString("N"), DisplayName = "Bob" };
        _users.TryAdd(u1.Id, u1);
        _users.TryAdd(u2.Id, u2);
        var g = new GroupDto { Id = Guid.NewGuid().ToString("N"), Name = "Demo Group", MemberUserIds = new List<string> { u1.Id, u2.Id } };
        _groups.TryAdd(g.Id, g);
        var m1 = NewMessage(u1.Id, u2.Id, null, MessageKind.Text, "Hi Bob");
        var m2 = NewMessage(u2.Id, u1.Id, null, MessageKind.Text, "Hello Alice");
        _messages.TryAdd(m1.Id, m1);
        _messages.TryAdd(m2.Id, m2);
    }

    public Task<UserDto> CreateUserAsync(string displayName, CancellationToken ct = default)
    {
        var id = Guid.NewGuid().ToString("N");
        var user = new UserDto { Id = id, DisplayName = displayName };
        _users[id] = user;
        return Task.FromResult(user);
    }

    public Task<UserDto?> GetUserAsync(string id, CancellationToken ct = default)
        => Task.FromResult(_users.TryGetValue(id, out var u) ? u : null);

    public Task<GroupDto> CreateGroupAsync(string name, IEnumerable<string> memberIds, CancellationToken ct = default)
    {
        var id = Guid.NewGuid().ToString("N");
        var group = new GroupDto { Id = id, Name = name, MemberUserIds = memberIds.Distinct().ToList() };
        _groups[id] = group;
        return Task.FromResult(group);
    }

    public Task<GroupDto?> GetGroupAsync(string id, CancellationToken ct = default)
        => Task.FromResult(_groups.TryGetValue(id, out var g) ? g : null);

    public Task AddUsersToGroupAsync(string groupId, IEnumerable<string> userIds, CancellationToken ct = default)
    {
        if (_groups.TryGetValue(groupId, out var g))
        {
            foreach (var id in userIds)
            {
                if (!g.MemberUserIds.Contains(id)) g.MemberUserIds.Add(id);
            }
        }
        return Task.CompletedTask;
    }

    public Task<MessageDto> AddMessageAsync(string fromUserId, string? toUserId, string? toGroupId, MessageKind kind, string content, CancellationToken ct = default)
    {
        var msg = NewMessage(fromUserId, toUserId, toGroupId, kind, content);
        _messages[msg.Id] = msg;
        return Task.FromResult(msg);
    }

    public Task<IReadOnlyList<MessageDto>> GetMessagesForUserAsync(string userId, int skip, int take, CancellationToken ct = default)
    {
        var items = _messages.Values
            .Where(m => m.ToUserId == userId || (m.ToGroupId != null && _groups.TryGetValue(m.ToGroupId, out var g) && g.MemberUserIds.Contains(userId)))
            .OrderBy(m => m.SentAt)
            .Skip(skip).Take(take)
            .ToList();
        return Task.FromResult<IReadOnlyList<MessageDto>>(items);
    }

    public Task<IReadOnlyList<MessageDto>> GetMessagesForGroupAsync(string groupId, int skip, int take, CancellationToken ct = default)
    {
        var items = _messages.Values
            .Where(m => m.ToGroupId == groupId)
            .OrderBy(m => m.SentAt)
            .Skip(skip).Take(take)
            .ToList();
        return Task.FromResult<IReadOnlyList<MessageDto>>(items);
    }

    private static MessageDto NewMessage(string fromUserId, string? toUserId, string? toGroupId, MessageKind kind, string content)
        => new()
        {
            Id = Guid.NewGuid().ToString("N"),
            FromUserId = fromUserId,
            ToUserId = toUserId,
            ToGroupId = toGroupId,
            Kind = kind,
            Content = content,
            SentAt = DateTimeOffset.UtcNow
        };
}
